﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Lucene.Net.Search;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using LuceneUtil = Lucene.Net.Util;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Cn;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Analysis.PanGu;

namespace XMK.Utils
{
    public enum LuceneAnalyzerType
    {
        Chinese,

        Standard,

        Pangu
    }

    public class LuceneQuery
    {
        public Query LuQuery
        {
            get;
            private set;
        }

        private LuceneQuery(Query query)
        {
            LuQuery = query;
        }

        /// <summary>
        /// 等于
        /// 对未分词的字段
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static LuceneQuery Eq(string fieldName, object value, float boost = 1.0f)
        {
            TermQuery termQuery = new TermQuery(new Term(fieldName, value.ToString()));
            termQuery.Boost = boost;
            return new LuceneQuery(termQuery);
        }

        /// <summary>
        /// 检索
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static LuceneQuery Lk(string fieldName, string value,
            LuceneAnalyzerType searchAnalzyerType, float boost = 1.0f)
        {
            Analyzer analyzer = null;
            switch (searchAnalzyerType)
            {
                case LuceneAnalyzerType.Chinese:
                    analyzer = new ChineseAnalyzer();
                    break;
                case LuceneAnalyzerType.Standard:
                    analyzer = new StandardAnalyzer(LuceneUtil.Version.LUCENE_30);
                    break;
                case LuceneAnalyzerType.Pangu:
                    //千万不要用 true 的重载
                    analyzer = new PanGuAnalyzer();
                    break;
            }
            QueryParser parser = new QueryParser(LuceneUtil.Version.LUCENE_30,
                fieldName, analyzer);
            Query query = parser.Parse(value);
            query.Boost = boost;
            return new LuceneQuery(query);
        }

        /// <summary>
        /// 多个条件与操作
        /// </summary>
        /// <param name="querys"></param>
        /// <returns></returns>
        public static LuceneQuery And(params LuceneQuery[] querys)
        {
            BooleanQuery boolQuery = new BooleanQuery();
            foreach (LuceneQuery item in querys)
            {
                if (item == null) continue;
                boolQuery.Add(item.LuQuery, Occur.MUST);
            }
            return new LuceneQuery(boolQuery);
        }

        /// <summary>
        /// 多个条件或操作
        /// </summary>
        /// <param name="querys"></param>
        /// <returns></returns>
        public static LuceneQuery Or(params LuceneQuery[] querys)
        {
            BooleanQuery boolQuery = new BooleanQuery();
            foreach (LuceneQuery item in querys)
            {
                if (item == null) continue;
                boolQuery.Add(item.LuQuery, Occur.SHOULD);
            }
            return new LuceneQuery(boolQuery);
        }

        public static LuceneQuery Gt(string fieldName, double d, float boost = 1.0f)
        {
            NumericRangeQuery<double> query = NumericRangeQuery.NewDoubleRange(fieldName, d, null, false, false);
            query.Boost = boost;
            return new LuceneQuery(query);
        }

        public static LuceneQuery Gte(string fieldName, double d, float boost = 1.0f)
        {
            NumericRangeQuery<double> query = NumericRangeQuery.NewDoubleRange(fieldName, d, null, true, false);
            query.Boost = boost;
            return new LuceneQuery(query
                );
        }

        public static LuceneQuery Gt(string fieldName, int d, float boost = 1.0f)
        {
            NumericRangeQuery<int> query = NumericRangeQuery.NewIntRange(fieldName, d, null, false, false);
            query.Boost = boost;
            return new LuceneQuery(query);
        }

        public static LuceneQuery Gte(string fieldName, int d, float boost = 1.0f)
        {
            NumericRangeQuery<int> query = NumericRangeQuery.NewIntRange(fieldName, d, null, true, false);
            query.Boost = boost;
            return new LuceneQuery(query);
        }

        public static LuceneQuery Gt(string fieldName, long d, float boost = 1.0f)
        {
            NumericRangeQuery<long> query = NumericRangeQuery.NewLongRange(fieldName, d, null, false, false);
            query.Boost = boost;
            return new LuceneQuery(query);
        }

        public static LuceneQuery Gte(string fieldName, long d, float boost = 1.0f)
        {
            NumericRangeQuery<long> query = NumericRangeQuery.NewLongRange(fieldName, d, null, true, false);
            query.Boost = boost;
            return new LuceneQuery(query);
        }

        public static LuceneQuery Between(string fieldName, long? start, long? end, float boost = 1.0f)
        {
            NumericRangeQuery<long> query = NumericRangeQuery.NewLongRange(fieldName, start, end, true, true);
            query.Boost = boost;
            return new LuceneQuery(query);
        }

        public static LuceneQuery Between(string fieldName, int? start, int? end, float boost = 1.0f)
        {
            NumericRangeQuery<int> query = NumericRangeQuery.NewIntRange(fieldName, start, end, true, true);
            query.Boost = boost;
            return new LuceneQuery(query);
        }

        /// <summary>
        /// 范围查询
        /// 针对日期的范围查询需要先将日期转换为数字
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static LuceneQuery Between(string fieldName, double? start, double? end, float boost = 1.0f)
        {
            NumericRangeQuery<double> query = NumericRangeQuery.NewDoubleRange(fieldName, start, end, true, true);
            query.Boost = boost;
            return new LuceneQuery(query);
        }

        /// <summary>
        /// 日期检索
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static LuceneQuery Between(string fieldName, DateTime start, DateTime end, float boost = 1.0f)
        {
            TermRangeQuery query = new TermRangeQuery(fieldName, start.ToString("yyyy-MM-dd"), end.ToString("yyyy-MM-dd"), true, true);
            query.Boost = boost;
            return new LuceneQuery(query);
        }
    }
}
